package com.beemans.corekit.integration.polling;

import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.util.Consumer;

import com.beemans.corekit.integration.toolkit.AppUtils;
import com.beemans.corekit.integration.toolkit.ThreadUtils;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;

public final class LocalPolling implements Handler.Callback {
    private static final int MSG_CODE = 1024;

    // 是否已初始化
    private static final AtomicBoolean isInitialized = new AtomicBoolean(false);

    private final Handler handler = new Handler(Looper.getMainLooper(), this);

    // 上一次检索时间戳
    private final AtomicLong lastCheckInterval = new AtomicLong(0);

    // 轮询检索间隔时间戳
    private long checkInterval = 15 * 1000;

    @Nullable
    private Consumer<Boolean> booleanConsumer;

    private LocalPolling() {
    }

    private static final class Holder {
        private static final LocalPolling INSTANCE = new LocalPolling();
    }

    static LocalPolling getInstance() {
        return Holder.INSTANCE;
    }

    @NonNull
    public static Builder build() {
        return new Builder();
    }

    public static class Builder {
        private long checkInterval = 15 * 1000;

        @Nullable
        private Consumer<Boolean> consumer;

        /**
         * @return 轮询间隔时间戳，单位：ms
         */
        public Builder setCheckInterval(long checkInterval) {
            this.checkInterval = checkInterval;
            return this;
        }

        /**
         * @return 轮询监听
         */
        public Builder setListener(@NonNull Consumer<Boolean> consumer) {
            this.consumer = consumer;
            return this;
        }

        public void create() {
            if (isInitialized.compareAndSet(false, true)) {
                ThreadUtils.runOnAsyncThread(() -> {
                    getInstance().lastCheckInterval.set(System.currentTimeMillis());
                    getInstance().checkInterval = checkInterval;
                    getInstance().booleanConsumer = consumer;

                    getInstance().sendHandleMessage();
                    getInstance().registerActionReceiver();

                    LocalPollingWorker.start();
                });
            }
        }
    }

    public void checkPolling(boolean isActionUserPresent) {
        final long now = System.currentTimeMillis();

        if (!isActionUserPresent) {
            final long last = lastCheckInterval.get();
            if (Math.abs(now - last) < checkInterval) {
                return;
            }
        }

        lastCheckInterval.set(now);

        // 防止 CPU 休眠
        WakeUtils.getInstance().acquire();

        if (booleanConsumer != null) {
            booleanConsumer.accept(isActionUserPresent);
        }

        sendHandleMessage();
    }

    private void sendHandleMessage() {
        handler.removeMessages(MSG_CODE);
        handler.removeCallbacksAndMessages(null);
        handler.sendEmptyMessageDelayed(MSG_CODE, checkInterval);
    }

    private void registerActionReceiver() {
        final Context appContext = AppUtils.getApp();
        if (appContext == null) {
            return;
        }

        registerScreenReceiver(appContext);
        registerPackageReceiver(appContext, () -> checkPolling(false));
        registerPowerReceiver(appContext, () -> checkPolling(false));
        registerVolumeReceiver(appContext, () -> checkPolling(false));
        registerOtherReceiver(appContext, () -> checkPolling(false));
    }

    private void registerOtherReceiver(
            @NonNull Context context,
            @NonNull Runnable runnable
    ) {
        final IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
        filter.addAction(Intent.ACTION_BATTERY_LOW);
        filter.addAction(Intent.ACTION_BATTERY_OKAY);
        filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        filter.addAction(Intent.ACTION_TIME_TICK);
        filter.addAction(Intent.ACTION_TIME_CHANGED);

        registerDefaultReceiver(context, filter, runnable);
    }

    private void registerVolumeReceiver(
            @NonNull Context context,
            @NonNull Runnable runnable
    ) {
        final IntentFilter filter = new IntentFilter();
        filter.addAction("android.media.VOLUME_CHANGED_ACTION");

        registerDefaultReceiver(context, filter, runnable);
    }

    private void registerPowerReceiver(
            @NonNull Context context,
            @NonNull Runnable runnable
    ) {
        final IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_POWER_CONNECTED);
        filter.addAction(Intent.ACTION_POWER_DISCONNECTED);

        registerDefaultReceiver(context, filter, runnable);
    }

    private void registerPackageReceiver(
            @NonNull Context context,
            @NonNull Runnable runnable
    ) {
        final IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        filter.addDataScheme("package");

        registerDefaultReceiver(context, filter, runnable);
    }

    private void registerScreenReceiver(@NonNull Context context) {
        try {
            final IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_USER_PRESENT);

            final ScreenOnReceiver screenOnReceiver = new ScreenOnReceiver();
            registerReceiver(context, screenOnReceiver, filter);
        } catch (Throwable ignored) {
        }
    }

    @SuppressLint("UnspecifiedRegisterReceiverFlag")
    private void registerDefaultReceiver(
            @NonNull Context context,
            @NonNull IntentFilter filter,
            @NonNull Runnable runnable
    ) {
        registerReceiver(context, new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                runnable.run();
            }
        }, filter);
    }

    private void registerReceiver(
            @NonNull Context context,
            @NonNull BroadcastReceiver receiver,
            @NonNull IntentFilter filter
    ) {
        try {
            ContextCompat.registerReceiver(context, receiver, filter, ContextCompat.RECEIVER_EXPORTED);
        } catch (Throwable ignored) {
        }
    }

    @Override
    public boolean handleMessage(@NonNull Message msg) {
        if (msg.what == MSG_CODE) {
            checkPolling(false);
            sendHandleMessage();
        }
        return false;
    }
}